#include "uart.c"

/*---- 内部使用函数 ----*/
/**
 * @brief 微秒级延时
 * @param t 微秒数（近似值）
 */
void lcd_delay_us(uint t)
{
    while (t--)
    {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    }
}

/**
 * @brief 毫秒级延时
 * @param t 毫秒数
 */
void lcd_delay_ms(uint t)
{
    uint i, j;
    for (i = 0; i < t; i++)
        for (j = 0; j < 114; j++)
            ;
}

/**
 * @brief 读取控制器忙状态
 */
bit LCD_ReadBusy(uchar controller)
{
    bit status;
    LCD_DATA = 0xFF; // 设置端口为输入

    LCD_RS = 0; // 命令模式
    LCD_RW = 1; // 读操作

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    LCD_E = 1;
    _nop_();
    _nop_();
    status = (LCD_DATA & 0x80) ? 1 : 0;
    LCD_E = 0;

    LCD_CS1 = LCD_CS2 = 0;
    LCD_RW = 0;

    return status;
}

/**
 * @brief 等待控制器就绪
 */
bit LCD_WaitReady(uchar controller, uint timeout)
{
    while (LCD_ReadBusy(controller))
    {
        if (timeout)
        {
            if (--timeout == 0)
                return 1;
        }
    }
    return 0;
}

/*---- 基础操作函数 ----*/
void lcd_write_command(uchar cmd, uchar controller)
{
    if (LCD_WaitReady(controller, 10000))
        return;

    LCD_RS = 0; // 命令模式
    LCD_RW = 0; // 写操作
    LCD_DATA = cmd;

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    LCD_E = 1;
    lcd_delay_us(2);
    LCD_E = 0;
}

void lcd_write_data(uchar dat, uchar controller)
{
    if (LCD_WaitReady(controller, 10000))
        return;

    LCD_RS = 1; // 数据模式
    LCD_RW = 0;
    LCD_DATA = dat;

    LCD_CS1 = (controller == 1);
    LCD_CS2 = (controller == 0);

    LCD_E = 1;
    lcd_delay_us(2);
    LCD_E = 0;
}

void lcd_init(void)
{
    lcd_delay_ms(50);
    //  0x3F : 0x3E;  // 选择显示开/关命令
    lcd_write_command(0x3F, 0); // 左屏开启
    lcd_write_command(0x3F, 1); // 右屏开启
    // 这个感觉设不设置没有什么变化？
    lcd_write_command(0xC0, 0); // 起始行
}

void lcd_clear_screen(void)
{
    uchar page, col;

    // 清左屏
    for (page = 0; page < 8; page++)
    {
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40, 0);
        for (col = 0; col < 64; col++)
            lcd_write_data(0x00, 0);
    }

    // 清右屏
    for (page = 0; page < 8; page++)
    {
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40, 1);
        for (col = 0; col < 64; col++)
            lcd_write_data(0x00, 1);
    }
}

/**
 * @brief LCD显示一个字节
 * @param page 页，0~7
 * @param col 列，0~127
 */
void lcd_display_one_byte_in_page(unsigned char page, unsigned char col, unsigned char oneByte)
{
    bit control = col >= 64;
    lcd_write_command(0xB8 | page, control);
    lcd_write_command(0x40 | col, control);
    lcd_write_data(oneByte, control);
}

/**
 * @brief LCD显示多个字节
 * @param page 页，0~7
 * @param col 列，0~127
 */
void lcd_display_bytes_in_page(unsigned char page, unsigned char col, uchar *bytes, uchar length)
{
    uchar i;

    if (col >= 64)
    {
        // 直接写到右侧屏幕
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40 | col, 1);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(bytes[i], 1);
        }
    }
    else if (col + length < 64)
    {
        // 直接写到左侧屏幕
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(bytes[i], 0);
        }
    }
    else
    {
        // 先写左侧
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < 64 - col; i++)
        {
            lcd_write_data(bytes[i], 0);
        }

        // 再写右侧
        lcd_write_command(0xB8 | page, 1);
        // 从右侧第0列开始写
        lcd_write_command(0x40, 1);
        for (i = 0; i < length - (64 - col); i++)
        {
            lcd_write_data(bytes[i + 64 - col], 1);
        }
    }
}

/**
 * @brief LCD显示多个字节
 * @param page 页，0~7
 * @param col 列，0~127
 * @param byte 显示数据
 * @param length 显示多长，最多不能超过128 - col
 */
void lcd_display_same_bytes_in_page(unsigned char page, unsigned char col, uchar oneByte, uchar length)
{
    uchar i;
    if (col >= 64)
    {
        // 直接写到右侧屏幕
        lcd_write_command(0xB8 | page, 1);
        lcd_write_command(0x40 | col, 1);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(oneByte, 1);
        }
    }
    else if (col + length < 64)
    {
        // 直接写到左侧屏幕
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < length; i++)
        {
            lcd_write_data(oneByte, 0);
        }
    }
    else
    {
        // 先写左侧
        lcd_write_command(0xB8 | page, 0);
        lcd_write_command(0x40 | col, 0);
        for (i = 0; i < 64 - col; i++)
        {
            lcd_write_data(oneByte, 0);
        }

        // 再写右侧
        lcd_write_command(0xB8 | page, 1);
        // 从右侧第0列开始写
        lcd_write_command(0x40, 1);
        for (i = 0; i < length - (64 - col); i++)
        {
            lcd_write_data(oneByte, 1);
        }
    }
}